Skip to content

[tools] feat: auto-select Keil/IAR target by Kconfig linker script - #11743

Open
nxp-ran wants to merge 7 commits into
RT-Thread:masterfrom
nxp-ran:feature/imxrt1180-keil-iar-target
Open

nxp-ran wants to merge 7 commits into
RT-Thread:masterfrom
nxp-ran:feature/imxrt1180-keil-iar-target

Conversation

@nxp-ran

@nxp-ran nxp-ran commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

拉取/合并请求描述:(PR description)

[

为什么提交这份PR (why to submit this PR)

i.MX RT1180 EVK BSP 通过 Kconfig 选择不同的链接脚本(RAM / FLEXSPI_NOR / HYPERRAM / FLEXSPI_NOR_HYPERRAM),并在 Keil/IAR 工程中对应不同的 target/configuration。此前生成的工程无法自动选中与所选链接脚本匹配的 target/配置,需要手动切换。本 PR 通过在通用工具中引入"可选板级钩子",让 BSP 自行决定激活哪个 target/配置,对不定义钩子的其他芯片零影响。

你的解决方案是什么 (what is your solution)

  • 板级专属逻辑(linker script -> target 名映射)放在 BSP 的 rtconfig.py。
  • 通用工具(tools/targets/keil.py、iar.py)只通过 hasattr(rtconfig, ...) 探测并调用可选钩子,用 try/except 守卫。
  • 未定义钩子的其他板子/芯片走原有代码路径,生成结果不变,向后兼容。

tools/targets/iar.py 改动详解

1. 工作区模板占位符改造

改动前:

iar_workspace = r'''... <path>$WS_DIR$\%s</path> ...'''
xml = iar_workspace % target

改动后:

iar_workspace = r'''...
  <project>
    <path>$WS_DIR$\%(project)s</path>
  </project>%(active_config)s
  <batchBuild/>
...'''
xml = iar_workspace % {'project': target, 'active_config': active_elem}

说明:把匿名占位符 %s 改为命名占位符,新增 %(active_config)s 用于插入 <activeConfig> 段。无激活配置时 active_elem 为空串,渲染结果与旧版逐字节一致,保证对其他板子无影响。

2. IARWorkspace 增加 active_config 参数

def IARWorkspace(target, active_config=None):
    workspace = target.replace('.ewp', '.eww')
    project_name = os.path.splitext(os.path.basename(target))[0]
    active_elem = ''
    if active_config:
        active_elem = '\n  <activeConfig>\n    <name>%s/%s</name>\n  </activeConfig>' % (project_name, active_config)
    out = open(workspace, 'w')
    xml = iar_workspace % {'project': target, 'active_config': active_elem}
    out.write(xml)
    out.close()

说明:新增可选参数(默认 None,向后兼容)。有配置时在 .eww 中写入 <activeConfig><name>项目名/配置名</name></activeConfig>,声明工程默认激活哪个 configuration。

3. 新增 _update_iar_wsdt() 函数

def _update_iar_wsdt(wsdt_path, project_name, active_config):
    config_str = '%s/%s' % (project_name, active_config)
    if not os.path.exists(wsdt_path):
        # 文件不存在则创建最小化 .wsdt
        os.makedirs(os.path.dirname(wsdt_path), exist_ok=True)
        content = '...<ConfigDictionary><CurrentConfigs><Project>%s</Project>...' % config_str
        with open(wsdt_path, 'w') as f:
            f.write(content)
        return
    try:
        tree = etree.parse(wsdt_path)
        root = tree.getroot()
        proj_elem = root.find('ConfigDictionary/CurrentConfigs/Project')
        if proj_elem is not None:
            proj_elem.text = config_str          # 已有节点直接改文本
        else:
            # 缺失则逐级补建 ConfigDictionary -> CurrentConfigs -> Project
            ...
        tree.write(wsdt_path, encoding='unicode', xml_declaration=True)
    except Exception as e:
        print('Warning: could not update %s: %s' % (wsdt_path, e))

说明:.wsdt 是 IAR 的会话文件,其 <CurrentConfigs><Project> 决定 IDE 实际选中的配置。只更新 .eww 不够,需同步 .wsdt。函数分"文件不存在则新建"和"文件存在则改/补节点"两种情况,出错只警告不中断。

4. IlinkConfigDefines 处理块(新增)

if name.text == 'IlinkConfigDefines':
    # write bare symbol=value tokens from LINKFLAGS as IAR linker defines
    import re
    for token in re.findall(r'\S+', LINKFLAGS):
        state = SubElement(option, 'state')
        state.text = token

说明:这是更新 IAR 工程的 IlinkConfigDefines 选项(对应 IDE 中 Linker -> Config -> Configuration file symbol definitions)。作用是把 SCons 收集到的 LINKFLAGS 里的链接器符号定义(如 symbol=value 这类给链接脚本用的宏)用 re.findall(r'\S+', ...) 按空白拆分成一个个 token,写成 <state> 子节点注入到该 option 下,使链接脚本依赖的符号能正确传给 ilinkarm。

注意:此块不受 active_config 守卫,对所有 IAR 板子生效;但仅当模板 .ewp 中存在 IlinkConfigDefines 选项且 LINKFLAGS 非空时才写入,多数板子该项为空、行为基本不变。

5. IARProject 中的钩子调用与文件复制(新增)

# 通过可选板级钩子获取激活配置
active_config = None
try:
    import rtconfig
    if hasattr(rtconfig, 'iar_get_active_config'):
        active_config = rtconfig.iar_get_active_config()
except Exception as e:
    print('Warning: could not get IAR active config: %s' % e)

IARWorkspace(target, active_config)

# 有配置时同步 settings/<project>.wsdt
if active_config:
    wsdt_path = os.path.join('settings', os.path.splitext(os.path.basename(target))[0] + '.wsdt')
    project_name = os.path.splitext(os.path.basename(target))[0]
    _update_iar_wsdt(wsdt_path, project_name, active_config)

# 复制 template.ewd(调试器设置) / template.ewt(构建设置) 到工程文件
import shutil
ewd_template = target.replace('.ewp', '.ewd').replace('project', 'template')
ewd_target   = target.replace('.ewp', '.ewd')
if not os.path.exists(ewd_template):
    ewd_template = 'template.ewd'
if os.path.exists(ewd_template):
    shutil.copy2(ewd_template, ewd_target)
# .ewt 同理

说明:

  • 钩子部分用 hasattr + try/except 守卫,其他芯片没有 iar_get_active_config 则 active_config 保持 None,.wsdt 更新整段跳过,行为不变。
  • .ewd/.ewt 复制:把调试器设置和构建设置从模板复制到实际工程文件,均有 os.path.exists 保护,模板不存在则安全跳过。此段不受 active_config 守卫,对所有 IAR 板子生效。

tools/targets/keil.py 改动详解

1. MDK45Project:多 Target 支持

改动前(只处理第一个 Target):

groups = tree.find('Targets/Target/Groups')
if groups is None:
    groups = SubElement(tree.find('Targets/Target'), 'Groups')
groups.clear()
...
IncludePath = tree.find('Targets/Target/.../IncludePath')
IncludePath.text = ...
Define = tree.find('Targets/Target/.../Define')
Define.text = ...

改动后(遍历所有 Target):

import copy
first_target = tree.find('Targets/Target')
groups = first_target.find('Groups')
if groups is None:
    groups = SubElement(first_target, 'Groups')
groups.clear()
...
include_path_text = ';'.join([...])
define_text = ', '.join(set(CPPDEFINES))
for target_node in tree.findall('Targets/Target'):
    # 把第一个 target 的 groups 深拷贝到其它 target,使各 target 共享同一份源文件列表
    if target_node is not first_target:
        existing_groups = target_node.find('Groups')
        if existing_groups is not None:
            target_node.remove(existing_groups)
        target_node.append(copy.deepcopy(groups))
    inc = target_node.find('.../IncludePath')
    if inc is not None:
        inc.text = include_path_text
    dfn = target_node.find('.../Define')
    if dfn is not None:
        dfn.text = define_text
    # uC99 / uGnu / Misc 同样在循环内、加 is not None 保护

说明:

  • 旧逻辑只给模板里第一个 Target 填充 groups/include/define/link flags,多 target 模板下其余 target 是空的。
  • 新逻辑先在第一个 target 构建 groups,再用 copy.deepcopy 复制到所有其它 target,并对每个 target 分别写入 IncludePath、Define、uC99、uGnu、Misc(链接选项)。
  • 所有 find 都加了 if ... is not None 空值保护,比旧版直接 .text = 更健壮。
  • 对单 target 模板(绝大多数板子):findall 只返回一个节点,target_node is first_target 恒为真,跳过 deepcopy,行为与旧版等价。

2. MDK5Project:复制 uvoptx 后调用可选钩子

改动前:

if os.path.exists('template.uvoptx'):
    import shutil
    shutil.copy2('template.uvoptx', '{}.uvoptx'.format(os.path.splitext(target)[0]))
    # build with UV4.exe
    if shutil.which('UV4.exe') is not None:
        ...

改动后:

if os.path.exists('template.uvoptx'):
    import shutil
    project_uvoptx = '{}.uvoptx'.format(os.path.splitext(target)[0])
    shutil.copy2('template.uvoptx', project_uvoptx)

    # 通过可选板级钩子设置激活 target
    try:
        import rtconfig
        if hasattr(rtconfig, 'update_keil_active_target'):
            rtconfig.update_keil_active_target(project_uvoptx)
    except Exception as e:
        print('Warning: could not set Keil active target: %s' % e)

    # build with UV4.exe
    if shutil.which('UV4.exe') is not None:
        ...

说明:复制得到 project.uvoptx 后,若 BSP 定义了 update_keil_active_target 钩子则调用它,把 .uvoptx 里匹配所选 linker script 的 target 的 <IsCurrentTarget> 置 1、其余置 0。用 hasattr + try/except 守卫,其他芯片跳过,行为不变。


bsp/nxp/imx/imxrt/imxrt1180-nxp-evk/cm33/rtconfig.py(cm7 同步)中的实现

1. linker script -> target/配置名映射表

# Keil target 与 IAR configuration 共用同一套名称
_LINKER_SCRIPT_TO_PROJECT_TARGET = {
    'RAM':                  'rtthread_ram',
    'FLEXSPI_NOR':          'rtthread_flexspi_nor',
    'FLEXSPI_NOR_HYPERRAM': 'rtthread_flexspi_nor_hyperram',
    # cm7 额外包含: 'HYPERRAM': 'rtthread_hyperram'
}

def _get_active_project_target():
    """Return the Keil target / IAR config name matching the selected linker script."""
    return _LINKER_SCRIPT_TO_PROJECT_TARGET.get(_LINKER_SCRIPT_TYPE, 'rtthread_ram')

2. Keil 钩子:设置激活 target

def update_keil_active_target(uvoptx_path='project.uvoptx'):
    """Set <IsCurrentTarget> in project.uvoptx to match the selected linker script."""
    import xml.etree.ElementTree as etree
    active = _get_active_project_target()
    if not os.path.exists(uvoptx_path):
        return
    tree = etree.parse(uvoptx_path)
    root = tree.getroot()
    for tgt in tree.findall('Target'):
        tname = tgt.find('TargetName')
        is_current = tgt.find('TargetOption/OPTFL/IsCurrentTarget')
        if tname is not None and is_current is not None:
            is_current.text = '1' if tname.text == active else '0'
    out = open(uvoptx_path, 'w')
    out.write('<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n')
    out.write(etree.tostring(root, encoding='utf-8').decode())
    out.close()
    print('Keil active target set to: ' + active)

3. IAR 钩子:返回激活 configuration 名

def iar_get_active_config():
    """Return the IAR configuration name matching the selected linker script.

    This hook is called by tools/targets/iar.py when generating the IAR
    project so that the active configuration follows the Kconfig linker
    script selection. It is board-specific and only defined here.
    """
    return _get_active_project_target()

说明:cm7/rtconfig.py 做同样改动,仅 target 映射表多一个 HYPERRAM 条目(cm7 特有)。原 cm7 里的 _LINKER_SCRIPT_TO_KEIL_TARGET 已统一重命名为 _LINKER_SCRIPT_TO_PROJECT_TARGET,并抽出 _get_active_project_target() 供两个钩子复用。


  • .config:
    CONFIG_BSP_LINKER_SCRIPT_RAM
    CONFIG_BSP_LINKER_SCRIPT_HYPERRAM
    CONFIG_BSP_LINKER_SCRIPT_FLEXSPI_NOR
    CONFIG_BSP_LINKER_SCRIPT_FLEXSPI_NOR_HYPERRAM

新增的功能也初步测试了其他项目生成IAR和KEIL工程的兼容性,包括bsp\nxp\imx\imxrt\imxrt1060-nxp-evk, bsp\nxp\mcx\mcxn\frdm-mcxn947 和 bsp\stm32\stm32h743-st-nucleo

]

当前拉取/合并请求的状态 Intent for your PR

必须选择一项 Choose one (Mandatory):

  • 本拉取/合并请求是一个草稿版本 This PR is for a code-review and is intended to get feedback
  • 本拉取/合并请求是一个成熟版本 This PR is mature, and ready to be integrated into the repo

代码质量 Code Quality:

我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:

  • 已经仔细查看过代码改动的对比 Already check the difference between PR and old code
  • 代码风格正确,包括缩进空格,命名及其他风格 Style guide is adhered to, including spacing, naming and other styles
  • 没有垃圾代码,代码尽量精简,不包含#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up
  • 所有变更均有原因及合理的,并且不会影响到其他软件组件代码或BSP All modifications are justified and not affect other components or BSP
  • 对难懂代码均提供对应的注释 I've commented appropriately where code is tricky
  • 代码是高质量的 Code in this PR is of high quality
  • 已经使用clang-format 源码格式化工具确保格式符合RT-Thread代码规范 This PR has been formatted with clang-format and complies with RT-Thread code specification
  • 如果是新增bsp, 已经添加ci检查到.github/ALL_BSP_COMPILE.json 详细请参考链接BSP自查

@nxp-ran
nxp-ran requested a review from Rbb666 as a code owner August 24, 2026 08:41
@github-actions

Copy link
Copy Markdown

👋 感谢您对 RT-Thread 的贡献!Thank you for your contribution to RT-Thread!

为确保代码符合 RT-Thread 的编码规范,请在你的仓库中执行以下步骤运行代码格式化工作流(如果格式化CI运行失败)。
To ensure your code complies with RT-Thread's coding style, please run the code formatting workflow by following the steps below (If the formatting of CI fails to run).


🛠 操作步骤 | Steps

  1. 前往 Actions 页面 | Go to the Actions page
    点击进入工作流 → | Click to open workflow →

  2. 点击 Run workflow | Click Run workflow

  • Use workflow from 保持默认分支(通常为 master)
    Keep the default branch (usually master) in Use workflow from
  • 在 branch 输入框填写 PR 分支 feature/imxrt1180-keil-iar-target
    Enter PR branch feature/imxrt1180-keil-iar-target in the branch field
  • 设置需排除的文件/目录(目录请以"/"结尾)
    Set files/directories to exclude (directories should end with "/")
  1. 等待工作流完成 | Wait for the workflow to complete
    格式化后的代码将作为独立提交推送至你的分支。
    The formatting changes will be pushed to your branch as a separate commit.

完成后,提交将自动更新至 feature/imxrt1180-keil-iar-target 分支,关联的 Pull Request 也会同步更新。
Once completed, commits will be pushed to the feature/imxrt1180-keil-iar-target branch automatically, and the related Pull Request will be updated.

如有问题欢迎联系我们,再次感谢您的贡献!💐
If you have any questions, feel free to reach out. Thanks again for your contribution!

@github-actions github-actions Bot added BSP: NXP Code related with NXP BSP tools labels Aug 24, 2026
@github-actions

github-actions Bot commented Aug 24, 2026 •

Copy link
Copy Markdown

Comment thread tools/targets/iar.py Outdated
Comment on lines +241 to +253
ewd_template = target.replace('.ewp', '.ewd').replace('project', 'template')
ewd_target = target.replace('.ewp', '.ewd')
if not os.path.exists(ewd_template):
ewd_template = 'template.ewd'
if os.path.exists(ewd_template):
shutil.copy2(ewd_template, ewd_target)

ewt_template = target.replace('.ewp', '.ewt').replace('project', 'template')
ewt_target = target.replace('.ewp', '.ewt')
if not os.path.exists(ewt_template):
ewt_template = 'template.ewt'
if os.path.exists(ewt_template):
shutil.copy2(ewt_template, ewt_target)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

新增逻辑从输出工程名推导模板路径。使用 --project-name=foo 时,第一次生成 foo.ewd,第二次会执行同文件复制并触发 SameFileError。模板源应固定解析为目标目录下的 template.ewd/template.ewt。

Comment thread tools/targets/keil.py Outdated
Comment on lines 383 to 406

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

钩子虽然正确更新了 project.uvoptx,但检测到 UV4.exe 后,构建逻辑仍固定读取模板中的第一个 Target。选择 FLEXSPI_NOR 时活动目标是 rtthread_flexspi_nor,实际传给 UV4.exe -t 的却仍是 rtthread_ram,可能生成错误镜像。

@nxp-ran

nxp-ran commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Hi @Rbb666
这边根据comment,已经做了修改。
请问这个PR还有什么问题吗?

@Rbb666

Rbb666 commented Sep 11, 2026

Copy link
Copy Markdown
Member

Hi @Rbb666 这边根据comment,已经做了修改。 请问这个PR还有什么问题吗?

还存在冲突,需要解决下

@nxp-ran

nxp-ran commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

Hi @Rbb666
解决了冲突。但是现在这两个错误似乎和我的PR无关。麻烦帮看一下。谢谢!

@Rbb666 Rbb666 closed this Sep 20, 2026
@Rbb666 Rbb666 reopened this Sep 20, 2026
@nxp-ran

nxp-ran commented Oct 12, 2026

Copy link
Copy Markdown
Contributor Author

Hi @Rbb666,
麻烦看一下这个错误,看上去不是我的修改导致的。谢谢!

Comment thread tools/targets/keil.py

Define = tree.find('Targets/Target/TargetOption/TargetArmAds/Cads/VariousControls/Define')
Define.text = ', '.join(set(CPPDEFINES))
dfn = target_node.find('TargetOption/TargetArmAds/Cads/VariousControls/Define')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里保留了循环体,却缺失循环和 define_text 初始化,单纯调整缩进仍会引用未定义变量。由于 targets/init.py 无条件导入 keil,IAR、CMake、Eclipse 等工程生成也会被阻断。应恢复完整循环及初始化。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

但是在292行和293行已经加上了如下代码:
include_path_text = ';'.join([_make_path_relative(project_path, os.path.normpath(i)) for i in set(CPPPATH)])
define_text = ', '.join(set(CPPDEFINES))

所以这个地方没有问题吧?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Rbb666 麻烦抽空看一下,谢谢!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

但是在292行和293行已经加上了如下代码: include_path_text = ';'.join([_make_path_relative(project_path, os.path.normpath(i)) for i in set(CPPPATH)]) define_text = ', '.join(set(CPPDEFINES))

所以这个地方没有问题吧?

当前文件中没有你提到的 include_path_text、define_text 初始化,也没有 for target_node ... 循环吧?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d4a86fc
这个commit还有,后面的commit似乎就消失了。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

66b15aa 这个commit merge的时候,把文件又改了回去

Comment thread tools/targets/iar.py Outdated
Comment on lines +201 to +206
if name.text == 'IlinkConfigDefines':
# write bare symbol=value tokens from LINKFLAGS as IAR linker defines
import re
for token in re.findall(r'\S+', LINKFLAGS):
state = SubElement(option, 'state')
state.text = token

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当 group 的 LINKFLAGS 包含 --keep=Reset_Handler 或 --config_def APP_OFFSET=0x1000 时,所有 token 都会进入 IlinkConfigDefines。已验证生成结果包含独立的 --config_def 等无效符号项;该字段只接受 symbol=value。应单独提取配置符号,或使用专用字段。

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. IAR IDE 在生成链接命令行时,会自动给这个字段的每个条目加上 --config_def

所以LINKFLAGS 里是不是就不应该有 --config_def 这些内容,而应该只是想要添加的宏?
就像现在bsp\nxp\imx\imxrt\imxrt1180-nxp-evk\cm33\board\SConscript中,关于LINKFLAGS的使用是如下实现的:

if rtconfig.PLATFORM in ['iccarm']:
    LINKFLAGS += ' __use_shmem__=1'
    LINKFLAGS += ' __multicore__=1'

而不是:

if rtconfig.PLATFORM in ['iccarm']:
    LINKFLAGS += '--config_def  __use_shmem__=1'
    LINKFLAGS += ' --config_def  __multicore__=1'
  1. --keep=Reset_Handler 这些内容,是不是就不应该出现在 LINKFLAGS 中? 而是属于LFLAGS?出现在LINKFLAGS 本身就错误使用,而不是应该iar.py 应该处理的事务?

  2. keil.py 的做法极其简单——不解析,整串透传:

# 收集所有 group 的 LINKFLAGS 拼成一整串
if 'LINKFLAGS' in group and group['LINKFLAGS']:
    LINKFLAGS += ' ' + group['LINKFLAGS']
...
# 原样塞进 LDads/Misc
misc = target_node.find('TargetOption/TargetArmAds/LDads/Misc')
misc.text = LINKFLAGS

而IAR这边因为没类似KEIL有misc这种灵活的方式。所以这边关于ILINK的配置,应该怎么处理更好?我只需要判断symbol=value这种情况,然后其他的都直接不处理吗?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 配置符号栏会由 IDE 转换为 --config_def 参数:这个是合理的,所以写入该栏的值应是 NAME=VALUE。
  2. --keep 应属于 LFLAGS,放进 LINKFLAGS 就是误用:不成立,BSP 的 SConstruct 会将 rtconfig.LFLAGS 赋给环境的 LINKFLAGS;DefineGroup() 又将组内 LINKFLAGS 追加到同一环境变量。
  3. IAR 没有类似 Keil Misc 的通用选项入口:RT1180 模板已经包含 IlinkExtraOptions 和 IlinkUseExtraOptions 了吧?
  4. 对于pr描述中的"对不定义钩子的其他芯片零影响":我执行了当前 IARProject(),输入:--keep=Reset_Handler --config_def APP_OFFSET=0x1000,生成的 IlinkConfigDefines 是包含三个独立条目的,包括错误的 --keep=Reset_Handler 和 --config_def。

@nxp-ran nxp-ran Oct 29, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. 我执行了当前 IARProject(),输入:--keep=Reset_Handler --config_def APP_OFFSET=0x1000,生成的 IlinkConfigDefines 是包含三个独立条目的,包括错误的 --keep=Reset_Handler 和 --config_def。

能否提供一下详细的测试情况? 我这边测试目前都是正常的。

另外,是否只要添加对NAME=VALUE的判断就行了?

@Rbb666 Rbb666 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前提交还有三处需要修改,见行内意见。Keil 的导入错误会影响其他工程生成器;IAR 的链接参数写入和 .wsdt 编码问题也已复现。请修复后重新验证工程生成和配置切换。

本次验证使用 Python 3.10、SCons 4.7 和仓库中的 cm33 IAR 模板,未进行 Keil/IAR 编译。

Comment thread tools/targets/keil.py
Define.text = ', '.join(set(CPPDEFINES))
dfn = target_node.find('TargetOption/TargetArmAds/Cads/VariousControls/Define')
if dfn is not None:
dfn.text = define_text

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] 这里仍然缺少外层 target 循环

当前提交在第 297 行直接报 IndentationError: unexpected indent。targets/__init__.py 会无条件导入 keil,所以连 import targets.iar 也会报同样的错误,IAR、CMake、Eclipse 等工程生成都会受影响。

请恢复完整的 target 遍历、define_text 初始化,以及其他 target 的 Groups 和 IncludePath 更新。只把这段缩进退回去还不够,target_node 和 define_text 仍然没有定义。

Comment thread tools/targets/iar.py Outdated
if name.text == 'IlinkConfigDefines':
# write bare symbol=value tokens from LINKFLAGS as IAR linker defines
import re
for token in re.findall(r'\S+', LINKFLAGS):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 不能把所有 LINKFLAGS 都当成配置符号

单独加载当前 iar.py,使用 cm33 的 template.ewp 调用 IARProject(),传入以下 group 即可复现:

{
    'name': 'ReviewProbe',
    'src': [],
    'LINKFLAGS': '--keep=Reset_Handler --config_def APP_OFFSET=0x1000',
}

生成的每个 configuration 的 IlinkConfigDefines 都新增了三个条目:--keep=Reset_Handler、--config_def、APP_OFFSET=0x1000。前两个是链接选项,不是该字段接受的配置符号;IlinkExtraOptions 则仍为空。

请单独提取配置符号,将普通链接选项写入 IlinkExtraOptions 并启用对应开关。仅判断是否包含 = 也不够,--keep=Reset_Handler 同样含有等号。这里没有板级钩子判断,没有定义钩子的 BSP 也会执行这段逻辑。

Comment thread tools/targets/iar.py Outdated
cur_cfgs = SubElement(cfg_dict, 'CurrentConfigs')
proj_elem = SubElement(cur_cfgs, 'Project')
proj_elem.text = config_str
tree.write(wsdt_path, encoding='unicode', xml_declaration=True)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] 写入 .wsdt 时需要显式指定 UTF-8

encoding='unicode' 配合文件路径会使用系统默认编码。在中文 Windows、Python 3.10、默认编码 CP936 下,首次创建 .wsdt 正常,第二次更新后文件头变成 encoding='cp936'。第三次切换配置时,前面的 etree.parse() 报 multi-byte encodings are not supported,异常被捕获后文件仍保留上一次的配置。

请改成 tree.write(wsdt_path, encoding='utf-8', xml_declaration=True),新建文件时也显式使用 UTF-8。已验证改用 UTF-8 后,连续切换三种配置可以正常更新。

nxp-ran and others added 3 commits November 13, 2026 14:25
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@nxp-ran

nxp-ran commented Nov 13, 2026

Copy link
Copy Markdown
Contributor Author

@Rbb666 已经修改好,麻烦审核一下。谢谢。

  1. Keil:恢复多 Target 遍历,保留上游头文件路径顺序。
  2. IAR 链接参数:将 --config_def 符号和其他链接选项分别写入对应字段;CM7/CM33 的符号定义改为显式使用 --config_def。
  3. IAR 会话文件:创建和更新 .wsdt 时统一使用 UTF-8。

@BernardXiong BernardXiong left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

结论:未发现新的阻塞问题;先前三点均已修复。 / Verdict: no new blockers; the three earlier items are addressed.

已在 head c5e01eca 复核增量与当前全量 diff:

  • keil.py:234 已恢复 Targets/Target 遍历,并按 target 写入 Groups/IncludePath/Define/Misc,P1 的 IndentationError 已消除;
  • iar.py:114 已把 --config_def 与普通链接选项分开,分别写入 IlinkConfigDefines / IlinkExtraOptions,P2 已处理;
  • iar.py:86 的 .wsdt 写入已显式使用 UTF-8 并覆盖新建路径,P2 已处理;
  • cm33/cm7 的 --config_def 拼写与 LINKFLAGS 空格拼接也与 IAR 参数格式一致。

验证缺口 / Gap: 按安全约定本轮未执行 PR 内的工程生成脚本,Keil/IAR 实际生成与配置切换仍需维护者或 CI 复验;CI 当前为绿色。Rbb666 的 CHANGES_REQUESTED 仍建议由其本人复核后解除。

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

BSP: NXP Code related with NXP BSP tools

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants